home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 2000 Reader Awards / macformat-098.iso / MF Data / MFCD / 00009_Dropdown List.ls < prev    next >
Encoding:
Text File  |  2000-11-01  |  16.8 KB  |  494 lines

  1. property spriteNum, mySprite, myName, myContent, myAction, myCheckmark, myStandard, myListMember, myField, myItemsList, myRestoreString, myDisplayString, myItemHeight, myOpenRect, myClosedRect, myClosedLoc, myOpenHeight, myStageHeight, myStageWidth, mySelectedItem, myListIsOpen, myClickTicks, myLastHilite
  2.  
  3. on getBehaviorDescription me
  4.   return "DROPDOWN LIST" & RETURN & RETURN & "Drop this behavior on a field member to create a pop-up list. " & "Animations continue while the the list is kept open." & RETURN & RETURN & "When the user clicks on the sprite, the dropdown list opens to reveal all its items. " & "If the user immediately releases the mouse, the menu remains open until the next click. " & "When the user selects a menu item, the menu closes up to displays the selected item. " & "If the user clicks elsewhere, the menu closes to display the previously selected item." & RETURN & RETURN & "You can use one of two modes for the dropdown list:" & RETURN & "1) To allow the user to make a selection." & RETURN & "2) To execute a simple command." & RETURN & RETURN & "SELECTION" & RETURN & RETURN & "In the first case, you will need to determine what the user selected. " & "To interrogate the dropdown list, use syntax similar to the following:" & RETURN & RETURN & "   put sendAllSprites (#DropList_Selection, 'listName')" & RETURN & RETURN & "This returns a property list with all the necessary information:" & RETURN & RETURN & "-- [#item: 1, #text: 'First choice', #type: #content, #sprite: 1]" & RETURN & RETURN & "See the Notes for developers in the script itself for more details." & RETURN & RETURN & "You can choose any character to act as a checkmark to indicate the previous selection when the dropdown list is open. " & "Depending on the font you use, you may wish to use a checkmark followed by a space. " & "Reopen the Behavior Parameters dialog to make such a change." & RETURN & RETURN & "EXECUTION" & RETURN & RETURN & "You can choose to execute three types of command:" & RETURN & "a) go marker (<selected item>)" & RETURN & "b) go movie '<selected item>'" & RETURN & "c) do '<selected item>'" & RETURN & RETURN & "The type of command depends on the contents of the list. " & "The behavior can automatically create a list of markers in the current movie, or movies in the current folder... " & "or it can leave the contents of the field as they are. " & "In this last case, choosing Execute makes the behavior treat the selected item as a Lingo command. " & "You should include handlers in a movie script to deal with such commands." & RETURN & RETURN & "TIP: Place the dropdown list sprite in a high channel where it will not be covered by any other sprites." & RETURN & RETURN & "PERMITTED MEMBER TYPES:" & RETURN & "field" & RETURN & RETURN & "PARAMETERS:" & RETURN & "* Name of the list (used in sendAllSprite calls)" & RETURN & "* Purpose - Choose between:" & RETURN & "  - Marker: creates a list of markers in current movie" & RETURN & "  - Movie: creates a list of movies with the same pathName" & RETURN & "  - Field contents: uses the current contents of the field" & RETURN & "* Action on selection - Choose between:" & RETURN & "  - Execute: go movie | go marker | do selectedLine" & RETURN & "  - Select:  return the selected item if called to do so" & RETURN & "* Checkmark to indicate currently selected item" & RETURN & "* Standard style: deselect this option if you want to give the field member a particular border, margin or shadow." & RETURN & RETURN & "PUBLIC METHODS:" & RETURN & "* Get info on currently selected item" & RETURN & "* Set the contents of the dropdown list" & RETURN & "* Toggle between Execute and Select modes" & RETURN & "* Get behavior reference"
  5. end
  6.  
  7. on getBehaviorTooltip me
  8.   return "Use with field members only." & RETURN & RETURN & "Turn a field into a pop-up list to execute commands or store selected data. " & "See the Behavior Description for tips on executing items with the 'do' command or accessing the currently selected item using Lingo." & RETURN & RETURN & "Options: Create a list of movies with the same path name, or a list of markers in the current movie."
  9. end
  10.  
  11. on beginSprite me
  12.   Initialize(me)
  13. end
  14.  
  15. on mouseDown me
  16.   if not myListIsOpen then
  17.     OpenList(me)
  18.   end if
  19. end
  20.  
  21. on prepareFrame me
  22.   CheckListState(me)
  23. end
  24.  
  25. on mouseUp me
  26.   CheckClick(me)
  27. end
  28.  
  29. on mouseUpOutSide me
  30.   CloseList(me)
  31. end
  32.  
  33. on CheckListState me
  34.   if myListIsOpen then
  35.     if the clickOn <> spriteNum then
  36.       CloseList(me)
  37.     else
  38.       HiliteSelection(me)
  39.     end if
  40.   else
  41.     if (myContent = #marker) and myAction then
  42.       markerNumber = GetCurrentMarker(me)
  43.       if mySelectedItem = markerNumber then
  44.         exit
  45.       end if
  46.       mySelectedItem = markerNumber
  47.       ScrollTo(me, mySelectedItem)
  48.     end if
  49.   end if
  50. end
  51.  
  52. on OpenList me
  53.   myClickTicks = the ticks
  54.   myListIsOpen = 1
  55.   myDisplayString = myRestoreString
  56.   if not myAction then
  57.     put myCheckmark into myDisplayString.line[mySelectedItem].char[1..2]
  58.   end if
  59.   myListMember.text = myDisplayString
  60.   currentScroll = myListMember.scrollTop
  61.   if myOpenHeight <= myStageHeight then
  62.     overShoot = currentScroll - myClosedLoc[2]
  63.     if overShoot < 0 then
  64.       overShoot = myOpenHeight - overShoot - myStageHeight
  65.       if overShoot < 0 then
  66.         mySprite.locV = myClosedLoc[2] - currentScroll
  67.       else
  68.         lineAdjust = ((overShoot - 1) / myItemHeight) + 1
  69.         pixelAdjust = (lineAdjust * myItemHeight) - overShoot
  70.         openTop = myStageHeight - myOpenHeight - pixelAdjust
  71.         mySprite.locV = openTop
  72.       end if
  73.     else
  74.       lineAdjust = ((overShoot - 1) / myItemHeight) + 1
  75.       pixelAdjust = lineAdjust * myItemHeight
  76.       openTop = pixelAdjust - overShoot
  77.       mySprite.locV = openTop
  78.     end if
  79.     myListMember.scrollTop = 0
  80.     myListMember.rect = myOpenRect
  81.   else
  82.     mySprite.locV = -2
  83.     clippedRect = myOpenRect.duplicate()
  84.     clippedRect[4] = myStageHeight
  85.     myListMember.rect = clippedRect
  86.     myListMember.boxType = #scroll
  87.     if mySprite.right > myStageWidth then
  88.       spriteWIdth = mySprite.right - mySprite.left
  89.       mySprite.locH = myStageWidth - spriteWIdth
  90.     end if
  91.     scrollAdjust = myClosedLoc[2] - mySprite.locV
  92.     myListMember.scrollTop = currentScroll - scrollAdjust
  93.   end if
  94.   updateStage()
  95. end
  96.  
  97. on HiliteSelection me
  98.   if the mouseMember <> myListMember then
  99.     if myLastHilite then
  100.       myLastHilite = 0
  101.       hilite char the maxinteger of field myField
  102.     end if
  103.     exit
  104.   else
  105.     if myListMember.boxType = #scroll then
  106.       AutoScroll(me)
  107.     end if
  108.     listLocV = mouseV() - mySprite.locV + myListMember.scrollTop
  109.     mouseItem = (listLocV / myItemHeight) + 1
  110.   end if
  111.   if mouseItem = myLastHilite then
  112.     exit
  113.   end if
  114.   if mouseItem > myItemsList.count then
  115.     myLastHilite = 0
  116.     hilite char the maxinteger of field myField
  117.     exit
  118.   end if
  119.   myLastHilite = mouseItem
  120.   if mouseItem = 1 then
  121.     firstCharToHilite = 1
  122.   else
  123.     textBeforeMouseItem = line 1 to mouseItem - 1 of myDisplayString
  124.     firstCharToHilite = the number of chars in textBeforeMouseItem + 2
  125.   end if
  126.   mouseItemLength = the number of chars in line mouseItem of myDisplayString
  127.   lastCharToHilite = firstCharToHilite + mouseItemLength
  128.   hilite char firstCharToHilite to lastCharToHilite of field myField
  129. end
  130.  
  131. on AutoScroll me
  132.   scrollDownHeight = myItemHeight / 2
  133.   scrollUpHeight = myStageHeight - (myItemHeight / 2)
  134.   currentScroll = myListMember.scrollTop
  135.   if mouseV() < scrollDownHeight then
  136.     if currentScroll <> 0 then
  137.       newScroll = currentScroll - scrollDownHeight
  138.       myListMember.scrollTop = max(0, newScroll)
  139.     end if
  140.   else
  141.     if mouseV() > scrollUpHeight then
  142.       maxScroll = myOpenHeight - myStageHeight
  143.       if currentScroll <> maxScroll then
  144.         newScroll = currentScroll + scrollDownHeight
  145.         myListMember.scrollTop = min(maxScroll, newScroll)
  146.       end if
  147.     end if
  148.   end if
  149. end
  150.  
  151. on CheckClick me
  152.   if (the ticks - myClickTicks) < 30 then
  153.     myClickTicks = 0
  154.   else
  155.     if myLastHilite then
  156.       mySelectedItem = myLastHilite
  157.     end if
  158.     CloseList(me)
  159.     if myAction and myLastHilite then
  160.       Execute(me)
  161.     end if
  162.   end if
  163.   myLastHilite = 0
  164. end
  165.  
  166. on ScrollTo me, theLine
  167.   myListMember.scrollTop = -10
  168.   myListMember.scrollTop = myItemHeight * (theLine - 1)
  169. end
  170.  
  171. on CloseList me
  172.   hilite char the maxinteger of field myField
  173.   if not myAction then
  174.     myListMember.text = myRestoreString
  175.   end if
  176.   mySprite.loc = myClosedLoc
  177.   myListMember.boxType = #fixed
  178.   myListMember.rect = myClosedRect
  179.   ScrollTo(me, mySelectedItem)
  180.   myListIsOpen = 0
  181.   if myContent <> #marker then
  182.     updateStage()
  183.   end if
  184. end
  185.  
  186. on Execute me
  187.   theItem = myItemsList[mySelectedItem]
  188.   case myContent of
  189.     #movie:
  190.       if not (the movieName starts theItem & ".") then
  191.         go(1, theItem)
  192.       end if
  193.     #marker:
  194.       go(myItemsList.getPropAt(mySelectedItem))
  195.     #content:
  196.       do(theItem)
  197.   end case
  198. end
  199.  
  200. on Initialize me
  201.   mySprite = sprite(me.spriteNum)
  202.   myListMember = mySprite.member
  203.   myField = myListMember.number
  204.   case myContent of
  205.     "Current contents of the field":
  206.       myContent = #content
  207.     "Markers in this movie":
  208.       myContent = #marker
  209.     "Movies with the same path name":
  210.       myContent = #movie
  211.   end case
  212.   case myAction of
  213.     "Select:  return the selected item when called":
  214.       myAction = 0
  215.     "Execute: go movie | go marker | do selectedLine":
  216.       myAction = 1
  217.   end case
  218.   myListMember.wordWrap = 0
  219.   myListMember.alignment = "left"
  220.   myListMember.boxType = #fixed
  221.   if myStandard then
  222.     myListMember.border = 1
  223.     myListMember.margin = 2
  224.     myListMember.boxDropShadow = 2
  225.   end if
  226.   CreateItems(me)
  227.   mySelectedItem = DefaultItem(me)
  228.   SetDimensions(me)
  229.   myListMember.rect = myClosedRect
  230.   ScrollTo(me, mySelectedItem)
  231. end
  232.  
  233. on CreateItems me
  234.   case myContent of
  235.     #content:
  236.       CreateContentsLists(me)
  237.     #marker:
  238.       myRestoreString = AddSpaces(me, the labelList)
  239.       myItemsList = GetMarkedFrames(me)
  240.     #movie:
  241.       myRestoreString = EMPTY
  242.       myItemsList = [:]
  243.       saveDelimiter = the itemDelimiter
  244.       the itemDelimiter = "."
  245.       CreateMovieLists(me, the moviePath)
  246.       the itemDelimiter = saveDelimiter
  247.   end case
  248. end
  249.  
  250. on AddSpaces me, theText
  251.   repeat while the last char in theText = RETURN
  252.     delete char -30000 of theText
  253.   end repeat
  254.   newString = EMPTY
  255.   lineCount = theText.line.count
  256.   repeat while lineCount
  257.     theItem = theText.line[lineCount]
  258.     put "   " & theItem & RETURN before newString
  259.     lineCount = lineCount - 1
  260.   end repeat
  261.   return newString
  262. end
  263.  
  264. on CreateContentsLists me
  265.   theText = myListMember.text
  266.   repeat while the last char in theText = RETURN
  267.     delete char -30000 of theText
  268.   end repeat
  269.   myRestoreString = EMPTY
  270.   myItemsList = [:]
  271.   lineCount = theText.line.count
  272.   repeat with i = 1 to lineCount
  273.     theItem = theText.line[i]
  274.     if SPACE & myCheckmark contains theItem.char[1] then
  275.       delete theText.char[1]
  276.       repeat while theItem.char[1] = " "
  277.         delete theText.char[1]
  278.       end repeat
  279.     end if
  280.     myRestoreString = myRestoreString & "   " & theItem & RETURN
  281.     myItemsList.addProp(i, theItem)
  282.   end repeat
  283. end
  284.  
  285. on GetMarkedFrames me
  286.   markerlist = [:]
  287.   sort(markerlist)
  288.   lastCheckedMarker = 0
  289.   if marker(1) <> marker(-(the maxinteger) / 2) then
  290.     repeat with i = 0 down to -(the maxinteger)
  291.       checkMarker = marker(i)
  292.       if checkMarker = lastCheckedMarker then
  293.         exit repeat
  294.       end if
  295.       lastCheckedMarker = checkMarker
  296.       markerlist.addProp(checkMarker, 0)
  297.     end repeat
  298.   end if
  299.   if marker(0) <> marker(the maxinteger / 2) then
  300.     repeat with i = 1 to the maxinteger
  301.       checkMarker = marker(i)
  302.       if checkMarker = lastCheckedMarker then
  303.         exit repeat
  304.       end if
  305.       lastCheckedMarker = checkMarker
  306.       markerlist.addProp(checkMarker, 0)
  307.     end repeat
  308.   end if
  309.   i = markerlist.count()
  310.   theLabels = the labelList
  311.   repeat while i
  312.     markerlist[i] = theLabels.line[i]
  313.     i = i - 1
  314.   end repeat
  315.   return markerlist
  316. end
  317.  
  318. on CreateMovieLists me, folderName
  319.   if the machineType = 256 then
  320.     fileDelimiter = "\"
  321.   else
  322.     fileDelimiter = ":"
  323.   end if
  324.   fileCount = 0
  325.   repeat while 1
  326.     fileCount = fileCount + 1
  327.     theFileName = getNthFileNameInFolder(folderName, fileCount)
  328.     if theFileName = EMPTY then
  329.       return 
  330.       next repeat
  331.     end if
  332.     case item 2 of theFileName of
  333.       "dir", "dxr", "dcr":
  334.         theMovie = item 1 of theFileName
  335.         myRestoreString = myRestoreString & "   " & theMovie & RETURN
  336.         movieCount = myItemsList.count() + 1
  337.         myItemsList.addProp(movieCount, theMovie)
  338.       otherwise:
  339.         CreateMovieLists(me, folderName & theFileName & fileDelimiter)
  340.     end case
  341.   end repeat
  342. end
  343.  
  344. on DefaultItem me
  345.   case myContent of
  346.     #content:
  347.       return 1
  348.     #marker:
  349.       return GetCurrentMarker(me)
  350.     #movie:
  351.       saveDelimiter = the itemDelimiter
  352.       the itemDelimiter = "."
  353.       shortName = item 1 of the movieName
  354.       the itemDelimiter = saveDelimiter
  355.       return myItemsList.getPos(shortName)
  356.   end case
  357. end
  358.  
  359. on SetDimensions me
  360.   saveLastChar = the last char in myRestoreString
  361.   delete char -30000 of myRestoreString
  362.   myListMember.text = myRestoreString
  363.   myItemHeight = myListMember.lineHeight
  364.   myOpenRect = myListMember.rect
  365.   myClosedRect = myOpenRect.duplicate()
  366.   myClosedRect[4] = myItemHeight + (myListMember.margin / 2)
  367.   myClosedLoc = mySprite.loc
  368.   addedHeight = (myListMember.margin * 2) + myListMember.boxDropShadow
  369.   myOpenHeight = myOpenRect.bottom + addedHeight
  370.   windowRect = (the activeWindow).rect
  371.   myStageHeight = windowRect.bottom - windowRect.top
  372.   myStageWidth = windowRect.right - windowRect.left
  373.   myRestoreString = myRestoreString & saveLastChar
  374.   myListMember.text = myRestoreString
  375. end
  376.  
  377. on GetCurrentMarker me
  378.   markerPosition = myItemsList.findPos(the frame)
  379.   if not markerPosition then
  380.     markerPosition = myItemsList.findPosNear(the frame) - 1
  381.   end if
  382.   return max(1, markerPosition)
  383. end
  384.  
  385. on DropList_Selection me, propListOrString
  386.   if stringp(propListOrString) then
  387.     if propListOrString <> myName then
  388.       exit
  389.     end if
  390.   end if
  391.   data = [#item: mySelectedItem, #text: myItemsList[mySelectedItem], #type: myContent, #sprite: spriteNum]
  392.   if ilk(propListOrString) <> #propList then
  393.     return data
  394.   else
  395.     propListOrString.addProp(myName, data)
  396.     return propListOrString
  397.   end if
  398. end
  399.  
  400. on DropList_SetContents me, theContents, theListName
  401.   if not voidp(theListName) then
  402.     if theListName <> myName then
  403.       exit
  404.     end if
  405.   end if
  406.   case ilk(theContents) of
  407.     #string:
  408.       myListMember.text = theContents
  409.       myContent = #content
  410.       Initialize(me)
  411.     #list:
  412.       listItems = EMPTY
  413.       lineCount = theContents.count
  414.       repeat with i = 1 to lineCount
  415.         theLine = string(theContents[i])
  416.         put theLine & RETURN after listItems
  417.       end repeat
  418.       myListMember.text = listItems
  419.       myContent = #content
  420.       Initialize(me)
  421.     #symbol:
  422.       case theContents of
  423.         #marker:
  424.           myContent = #marker
  425.           Initialize(me)
  426.         #movie:
  427.           myContent = #movie
  428.           Initialize(me)
  429.         otherwise:
  430.           return #invalidListContents
  431.       end case
  432.     otherwise:
  433.       return #invalidListContents
  434.   end case
  435. end
  436.  
  437. on DropList_ToggleExecution me, executeMode, listName
  438.   if not voidp(listName) then
  439.     if listName <> myName then
  440.       exit
  441.     end if
  442.   else
  443.     if stringp(executeMode) then
  444.       if executeMode = myName then
  445.         myAction = not myAction
  446.       else
  447.         exit
  448.       end if
  449.     end if
  450.   end if
  451.   if voidp(executeMode) then
  452.     myAction = not myAction
  453.   else
  454.     case executeMode of
  455.       #Execute, 1:
  456.         myAction = 1
  457.       #select, 0:
  458.         myAction = 0
  459.       otherwise:
  460.         return #invalidExecuteMode
  461.     end case
  462.   end if
  463. end
  464.  
  465. on DropList_GetReference me, propListOrString
  466.   case ilk(propListOrString) of
  467.     #propList:
  468.       propListOrString.addProp(myName, me)
  469.       return propListOrString
  470.     #string:
  471.       if propListOrString = myName then
  472.         return me
  473.       end if
  474.     otherwise:
  475.       return me
  476.   end case
  477. end
  478.  
  479. on isOKToAttach me, aSpriteType, aSpriteNum
  480.   case aSpriteType of
  481.     #graphic:
  482.       return getPos([#field], sprite(aSpriteNum).member.type) <> 0
  483.     #script:
  484.       return 0
  485.   end case
  486. end
  487.  
  488. on getPropertyDescriptionList me
  489.   if not (the currentSpriteNum) then
  490.     exit
  491.   end if
  492.   return [#myName: [#comment: "Name of this list", #format: #string, #default: "List" & the currentSpriteNum], #myContent: [#comment: "Contents of list", #format: #string, #range: ["Current contents of the field", "Markers in this movie", "Movies with the same path name"], #default: "Current contents of the field"], #myAction: [#comment: "Purpose of list", #format: #string, #range: ["Select:  return the selected item when called", "Execute: go movie | go marker | do selectedLine"], #default: "Select:  return the selected item when called"], #myCheckmark: [#comment: "Checkmark to indicate currently selected item", #format: #string, #default: ">"], #myStandard: [#comment: "Use standard style?", #format: #boolean, #default: 1]]
  493. end
  494.